home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 076-100 / disk_085 / filereq / stdfile.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  22KB  |  938 lines

  1. /* STDFILE -- Standard File Requestor. Version 2.0a 15 June 1987
  2.  *
  3.  * AUTHOR -- Peter da Silva      US (713) 497-4372
  4.  *
  5.  * Copyright (c) 1987 Peter da Silva, all rights reserved.
  6.  *
  7.  *    This module may be freely used in any product, commercial or
  8.  *    otherwise, provided credit is given for this module and
  9.  *    and provided this notice remains intact in the source. The
  10.  *    intent of this module is to provide a standard file requestor
  11.  *    such as is available on the Macintosh, in GEM on the IBM-PC
  12.  *    and Atari ST, and in the Microsoft Windows software on the
  13.  *    IBM-PC. The advantage this module has over other requestors
  14.  *    is that it minimises disk accesses: an important consideration
  15.  *    given the structure of AmigaDos directories. If you need to
  16.  *    modify it for your needs, by all means go ahead... but please
  17.  *    conform to the intent of this program as stated above. If you
  18.  *    have suggestions for improvements, by all means call me at
  19.  *    the number listed above.
  20.  *
  21.  * Enhancements in the current version:
  22.  *
  23.  *    Gadgets now boxed. Display generally cleaned up.
  24.  *
  25.  *    True "dictionary order" for searches.
  26.  *
  27.  *    Default pattern can now be specified. Default file name now
  28.  *    specified in a single argument.
  29.  *
  30.  *    Directories always match.
  31.  *
  32.  *    Null pattern converted to "#?" universal wildcard.
  33.  *
  34.  *    If you attempt to build a file name longer than 128 characters the
  35.  *    screen will flash and the operation will be aborted.
  36.  *
  37.  *    "Volumes" gadget, using the device list code in "mounted". This
  38.  *    gadget brings up a list of all currently mounted volumes for
  39.  *    selection. Volumes leaves the directory specification intact, so
  40.  *    you can quickly return to where you left off.
  41.  *
  42.  *    "Parent" gadget, displays parent directory.
  43.  *
  44.  *    With these enhancements it is now possible to select any file on
  45.  *    any device without touching the keyboard. This is now release 2.0,
  46.  *    as it is significantly better than 1.0.
  47.  *
  48.  * Acknowledgements:
  49.  *
  50.  *    Thanks to Jeff Lydiatt for the pattern matching code in PatMatch.c
  51.  *    Thanks to Jay Miner, =RJ= and the whole Amiga team for the Amiga
  52.  *    itself.
  53.  *
  54.  * Environment:
  55.  *
  56.  *    IntuitionBase and GfxBase must be open. dos.library must be open
  57.  *    under the name "DOSBase". Link with PatMatch.o and VolList.o.
  58.  *
  59.  * Usage:
  60.  *
  61.  *    #define MAXFILENAME 128
  62.  *
  63.  *    int stdfile(title, default_file, default_pat, name);
  64.  *    char *title;
  65.  *    char *default_file;
  66.  *    char *default_pattern;
  67.  *    char name[MAXFILENAME];
  68.  *
  69.  *    struct Screen *stdscreen;
  70.  *
  71.  *    STDFILE puts up a file requestor (actually, it's a plain window)
  72.  *    in stdscreen. If stdscreen is NULL, the workbench screen is used.
  73.  *    The requestor looks like this (allowing for the limitations of
  74.  *    text):
  75.  *
  76.  *    +-----------------------------------+
  77.  *    |o| Title ------------------- |  |  | title parameter, or "File Name"
  78.  *    |-----------------------------------|
  79.  *    | Directory: [                    ] | Directory parameter, or current.
  80.  *    | File name: [                    ] | Default parameter, or empty.
  81.  *    | Pattern:   [                    ] | Initially empty, if the user
  82.  *    | +-------------------------------+ | enters anything here it will
  83.  *    | | [Filename]                 |  | | be used to select files. The
  84.  *    | | [Filename]                 |  | | file display will also be empty
  85.  *    | | [Filename]                 |@@| | to start with to avoid excess
  86.  *    | | [Filename]                 |@@| | disk I/O. If the user selects
  87.  *    | |                            |@@| | here the directory will be
  88.  *    | |                            |@@| | scanned looking for files
  89.  *    | |                            |  | | matching the specified pattern,
  90.  *    | |                            |  | | or "#?" if no pattern is given.
  91.  *    | |                            |  | |
  92.  *    | +-------------------------------+ | ACCEPT returns 1. CANCEL
  93.  *    | [ACCEPT]    [VOLUMES]    [CANCEL] | or the close gadget return 0.
  94.  *    +-----------------------------------+ VOLUMES displays volume names.
  95.  *
  96.  *    The number of filenames displayed is specified at compile time in the
  97.  *    constant MAXFILES. The maximum size of a filename is specified in the
  98.  *    constant MAXNAME. The parameter "Default file" will be broken into
  99.  *    directory and file parts.
  100.  */
  101. char *Copyright =
  102. "stdfile V2.0a. Copyright (c) 1987 Peter da Silva. All rights reserved.";
  103. #include <intuition/intuitionbase.h>
  104. #include <intuition/intuition.h>
  105. #include <libraries/dos.h>
  106. #include <exec/memory.h>
  107.  
  108. char *malloc();
  109.  
  110. #define MAXFILES 8
  111. #define MAXNAME 32
  112. #define MAXFULL (MAXNAME*4)
  113.  
  114. /* SIZING PARAMS */
  115. #define Z NULL
  116. #define INDENT 6
  117. #define LEFTMAR (INDENT-1)
  118. #define BORDER 3
  119. #define CHSIZ 8
  120. #define HT CHSIZ
  121. #define BASELINE 6
  122. #define BUTWID (6*CHSIZ+INDENT*2)
  123.  
  124. /* GADGET BORDERS */
  125. #define IN1 LEFTMAR+10*CHSIZ
  126. #define IN3 LEFTMAR+3
  127. #define IN4 -(INDENT+6*CHSIZ+1)
  128. #define IN5 -(INDENT+CHSIZ*2)
  129. #define IN6 ((WINWD-BUTWID)/3+INDENT)
  130. #define IN7 (((WINWD-BUTWID)*2)/3+INDENT)
  131. #define WD1 -(INDENT+IN1)
  132. #define WD3 (6*CHSIZ)
  133. #define WD4 (6*CHSIZ)
  134. #define WD5 (CHSIZ*2+2)
  135. #define WD6 (6*CHSIZ)
  136. #define WD7 (6*CHSIZ)
  137. #define TP1 (CHSIZ+BORDER)
  138. #define TP2 (TP1+HT+1)
  139. #define TP3 (TP2+HT+1)
  140. #define TP4 -(BORDER+HT4-1)
  141. #define TP5 (TP3+HT+BORDER)
  142. #define HT4 (HT+1)
  143. #define HT5 CHSIZ*MAXFILES+INDENT
  144.  
  145. #define WINHT (TP5 + HT5 + (-TP4) + BORDER)
  146. #define WINWD (INDENT*4 + (MAXNAME+2)*CHSIZ)
  147. #define WININ (640-WINWD)/2
  148. #define WINTP (200-WINHT)/2
  149.  
  150. #define HOMEX (INDENT+LEFTMAR)
  151. #define HOMEY (TP5+BORDER)
  152. #define LASTX (HOMEX+MAXNAME*CHSIZ)
  153. #define LASTY (HOMEY+MAXFILES*CHSIZ)
  154.  
  155. #define BTP TP5
  156. #define BIN LEFTMAR
  157. #define BWD (WINWD-INDENT-BIN)
  158. #define BHT (WINHT-BTP-(-TP4+BORDER+1))
  159.  
  160. #define SF GADGHCOMP|GRELWIDTH
  161. #define SEL SELECTED
  162. #define BF1 GADGHCOMP|GRELBOTTOM
  163. #define BF2 GADGHCOMP|GRELBOTTOM|GRELRIGHT
  164. #define PF GRELRIGHT
  165.  
  166. #define SA RELVERIFY
  167. #define CEN STRINGCENTER
  168. #define BA RELVERIFY
  169. #define PA RELVERIFY
  170.  
  171. #define SI(n) (APTR)&STD_String[n]
  172. #define G(n) &STD_Gadget[n]
  173. #define IMAG (APTR)&STD_Image
  174. #define PROP (APTR)&STD_Prop
  175.  
  176. #define SG STRGADGET
  177. #define BG BOOLGADGET
  178. #define PG PROPGADGET
  179.  
  180. #define FP AUTOBACKPEN
  181. #define BP AUTOFRONTPEN
  182.  
  183. #define OKTEXT &STD_OK
  184. #define NOTEXT &STD_CANCEL
  185. #define VLTEXT &STD_VOLUME
  186. #define PRTEXT &STD_PARENT
  187.  
  188. static int DoneFlag;
  189.  
  190. #define DirName SBuffer[0]
  191. #define FileName SBuffer[1]
  192. #define PatName SBuffer[2]
  193. #define STRINGS 3
  194.  
  195. static UBYTE SBuffer[STRINGS][MAXFULL];
  196. static UBYTE Undo[MAXFULL];
  197.  
  198. static struct StringInfo STD_String[STRINGS] = {
  199.     {SBuffer[0],Undo,0,MAXFULL,0},
  200.     {SBuffer[1],Undo,0,MAXFULL,0},
  201.     {SBuffer[2],Undo,0,MAXFULL,0}
  202. };
  203.  
  204. static struct PropInfo STD_Prop = { AUTOKNOB|FREEVERT, 0, 0, 0, 0 };
  205.  
  206. static struct IntuiText STD_OK =
  207.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"ACCEPT", Z };
  208. static struct IntuiText STD_CANCEL =
  209.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"CANCEL", Z };
  210. static struct IntuiText STD_VOLUME =
  211.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"VOLUME", Z };
  212. static struct IntuiText STD_PARENT =
  213.     { FP, BP, JAM2, 0, 1, Z, (UBYTE *)"PARENT", Z };
  214.  
  215. #define BUTTONS 4
  216. #define BUTVEC 8
  217.  
  218. static SHORT butvecs[BUTTONS][BUTVEC*2] = {
  219.     {
  220.         -2, HT4,
  221.         -2, -1,
  222.         WD3+1,-1,
  223.         WD3+1,HT4,
  224.         -3, HT4,
  225.         -3,-1,
  226.         WD3+2,-1,
  227.         WD3+2, HT4
  228.     },
  229.     {
  230.         -2, HT4,
  231.         -2, -1,
  232.         WD4+1,-1,
  233.         WD4+1,HT4,
  234.         -3, HT4,
  235.         -3,-1,
  236.         WD4+2,-1,
  237.         WD4+2, HT4
  238.     },
  239.     {
  240.         -2, HT4,
  241.         -2, -1,
  242.         WD6+1,-1,
  243.         WD6+1,HT4,
  244.         -3, HT4,
  245.         -3,-1,
  246.         WD6+2,-1,
  247.         WD6+2, HT4
  248.     },
  249.     {
  250.         -2, HT4,
  251.         -2, -1,
  252.         WD7+1,-1,
  253.         WD7+1,HT4,
  254.         -3, HT4,
  255.         -3,-1,
  256.         WD7+2,-1,
  257.         WD7+2, HT4
  258.     }
  259. };
  260. static struct Border ButBorder[BUTTONS] = {
  261.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[0], NULL},
  262.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[1], NULL},
  263.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[2], NULL},
  264.     {0, 0, FP, BP, JAM1, BUTVEC, butvecs[3], NULL}
  265. };
  266. #define BB(n) &ButBorder[n]
  267.  
  268. static struct Image STD_Image;
  269.  
  270. #define DIRID 0
  271. #define FILID 1
  272. #define PATID 2
  273. #define YESID 3
  274. #define CANID 4
  275. #define VOLID 5
  276. #define PARID 6
  277. #define BARID 7
  278. #define GADGETS 8
  279.  
  280. static struct Gadget STD_Gadget[GADGETS] = {
  281. /*NEXT, LFT, TP,WDTH, H, FLAG,  ACT, TYP, REND, Z, TXT, Z, SPEC, ID, Z */
  282. { G(1), IN1,TP1, WD1,HT, SF,     SA,  SG,    Z, Z,   Z, Z, SI(0), 0, 0 },
  283. { G(2), IN1,TP2, WD1,HT, SF|SEL, SA,  SG,    Z, Z,   Z, Z, SI(1), 1, 0 },
  284. { G(3), IN1,TP3, WD1,HT, SF,     SA,  SG,    Z, Z,   Z, Z, SI(2), 2, 0 },
  285. { G(4), IN3,TP4, WD3,HT4,BF1,    BA,  BG,BB(0), Z, OKTEXT, Z,  Z, 3, 0 },
  286. { G(5), IN4,TP4, WD4,HT4,BF2,    BA,  BG,BB(1), Z, NOTEXT, Z,  Z, 4, 0 },
  287. { G(6), IN6,TP4, WD6,HT4,BF1,    BA,  BG,BB(2), Z, VLTEXT, Z,  Z, 5, 0 },
  288. { G(7), IN7,TP4, WD7,HT4,BF1,    BA,  BG,BB(3), Z, PRTEXT, Z,  Z, 6, 0 },
  289. { NULL, IN5,TP5, WD5,HT5,PF,     PA,  PG, IMAG, Z,   Z, Z,  PROP, 7, 0 }
  290. };
  291.  
  292. static struct NewWindow STD_NewWindow = {
  293.     WININ, WINTP, WINWD, WINHT, -1, -1,
  294.     REFRESHWINDOW|MOUSEBUTTONS|GADGETUP|CLOSEWINDOW,
  295.     WINDOWDRAG|WINDOWDEPTH|WINDOWCLOSE|SIMPLE_REFRESH|ACTIVATE,
  296.     G(0), NULL, "File Name Requestor",
  297.     NULL, NULL, 0, 0, 0, 0, WBENCHSCREEN
  298. };
  299. static struct Window *STD_Window;
  300.  
  301. #define NVEC 6
  302.  
  303. static SHORT Vectors[NVEC*2] = {
  304.     BIN+1, BTP,
  305.     BIN+1, BTP+BHT,
  306.     BIN+BWD, BTP+BHT,
  307.     BIN+BWD, BTP,
  308.     BIN, BTP,
  309.     BIN, BTP+BHT
  310. };
  311.  
  312. static struct Border STD_FileBox = {
  313.     0, 0, FP, BP, JAM1, NVEC, Vectors, NULL
  314. };
  315.  
  316. static struct IntuiText STD_Text[3] = {
  317.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Directory:", NULL },
  318.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"File Name:", NULL },
  319.     { FP, BP, JAM2, 0, 0, NULL, (UBYTE *)"Pattern:", NULL }
  320. };
  321.  
  322. static OpenFileWindow()
  323. {
  324.     extern struct IntuitionBase *IntuitionBase;
  325.     int i;
  326.  
  327.     /* Rebuild gadget list */
  328.     STD_NewWindow.FirstGadget = &STD_Gadget[0];
  329.     for(i = 0; i < GADGETS; i++) {
  330.         STD_Gadget[i].NextGadget = (i==GADGETS-1)?(0):(&STD_Gadget[i+1]);
  331.     }
  332.     for(i = 0; i < STRINGS; i++) {
  333.         STD_String[i].BufferPos = strlen(SBuffer[i]);
  334.         STD_String[i].DispPos = 0;
  335.     }
  336.     STD_Prop.VertBody = 0xFFFF;
  337.     STD_Prop.VertPot = 0;
  338.  
  339.     if(!(STD_Window = OpenWindow(&STD_NewWindow))) {
  340.         return 0;
  341.     }
  342.  
  343.     /* This optional line will activate a string gadget    */
  344.     if ( IntuitionBase->lib_Version > 32 )
  345.     {
  346.         ActivateGadget(G(1),STD_Window,0L);
  347.     }
  348.  
  349.     CalcPropGadget();
  350.     PaintFileWindow();
  351.     return 1;
  352. }
  353.  
  354. static CloseFileWindow()
  355. {
  356.     STD_NewWindow.LeftEdge = STD_Window->LeftEdge;
  357.     STD_NewWindow.TopEdge = STD_Window->TopEdge;
  358.     if(STD_Window)
  359.         CloseWindow(STD_Window);
  360. }
  361.  
  362. static int State;
  363.  
  364. #define INITIAL 0
  365. #define DIRECTORY 1
  366.  
  367. static PaintFileWindow()
  368. {
  369.     DrawBorder(STD_Window->RPort, &STD_FileBox, 0, 0);
  370.     PrintIText(STD_Window->RPort, &STD_Text[0], LEFTMAR, TP1);
  371.     PrintIText(STD_Window->RPort, &STD_Text[1], LEFTMAR, TP2);
  372.     PrintIText(STD_Window->RPort, &STD_Text[2], LEFTMAR, TP3);
  373.     if(State == DIRECTORY) PrintFileNames();
  374. }
  375.  
  376. static int FirstFile;
  377. static int Selected;
  378. static int NumFiles;
  379. static struct dirent {
  380.     struct dirent *nextfile;
  381.     SHORT filetype;
  382.     char *filename;
  383. } *NameList, **NameTable;
  384.  
  385. #define FILETYPE 0
  386. #define DIRTYPE 1
  387. #define VOLTYPE 2
  388.  
  389. static PrintFileNames()
  390. {
  391.     int i;
  392.  
  393.     for(i = 0; i < MAXFILES; i++) {
  394.         SetBPen(STD_Window->RPort, BP);
  395.         SetAPen(STD_Window->RPort, BP);
  396.         RectFill(STD_Window->RPort,
  397.             HOMEX, HOMEY+i*CHSIZ,
  398.             LASTX, HOMEY+(i+1)*CHSIZ);
  399.         if(i+FirstFile < NumFiles)
  400.             PrintName(i+FirstFile, i+FirstFile==Selected);
  401.     }
  402. }
  403.  
  404. static PrintName(file, hilite)
  405. int file;
  406. int hilite;
  407. {
  408.     int i;
  409.  
  410.     i = file - FirstFile;
  411.  
  412.     Move(STD_Window->RPort, HOMEX, HOMEY+i*CHSIZ+BASELINE);
  413.     if(hilite == 0) {
  414.         SetBPen(STD_Window->RPort, BP);
  415.         if(NameTable[file]->filetype == FILETYPE)
  416.             SetAPen(STD_Window->RPort, FP);
  417.         else
  418.             SetAPen(STD_Window->RPort, 3);
  419.     } else {
  420.         SetAPen(STD_Window->RPort, BP);
  421.         if(NameTable[file]->filetype == FILETYPE)
  422.             SetBPen(STD_Window->RPort, FP);
  423.         else
  424.             SetBPen(STD_Window->RPort, 3);
  425.     }
  426.     Text(STD_Window->RPort,
  427.         NameTable[file]->filename,
  428.         strlen(NameTable[file]->filename));
  429. }
  430.  
  431. static CalcPropGadget()
  432. {
  433.     int VertPot, VertBody;
  434.  
  435.     if(State == INITIAL) return;
  436.  
  437.     if(NumFiles<=MAXFILES) {
  438.         VertBody = 0xFFFF;
  439.         VertPot = 0;
  440.         FirstFile = 0;
  441.     } else {
  442.         VertBody = ((MAXFILES<<16)-1) / NumFiles;
  443.         VertPot = 0;
  444.         FirstFile = 0;
  445.     }
  446.  
  447.     ModifyProp(&STD_Gadget[BARID], STD_Window, NULL,
  448.         STD_Prop.Flags, 0, VertPot, 0, VertBody);
  449. }
  450.  
  451. static CalcFilePosition()
  452. {
  453.     int old_pos;
  454.  
  455.     if(State == INITIAL) return;
  456.  
  457.     old_pos = FirstFile;
  458.     if(NumFiles<=MAXFILES)
  459.         FirstFile = 0;
  460.     else {
  461.         int VertPot = STD_Prop.VertPot;
  462.  
  463.         FirstFile = ((VertPot+1)*(NumFiles-MAXFILES))>>16;
  464.     }
  465.     if(old_pos != FirstFile)
  466.         PrintFileNames();
  467. }
  468.  
  469. FreeList(list)
  470. struct dirent *list;
  471. {
  472.     struct dirent *ptr;
  473.  
  474.     while(list) {
  475.         ptr = list->nextfile;
  476.         if(list->filename) free(list->filename);
  477.         free(list);
  478.         list = ptr;
  479.     }
  480. }
  481.  
  482. static ReadNewDir()
  483. {
  484.     struct dirent *NewList, **NewTable, *ptr;
  485.     int NewCount;
  486.     struct FileInfoBlock *FIB;
  487.     BPTR dirlock;
  488.  
  489.     if(State != DIRECTORY) {
  490.         NameTable = 0;
  491.         NameList = 0;
  492.     }
  493.     if(DirName[0])
  494.         dirlock = Lock(DirName, ACCESS_READ);
  495.     else {
  496.         BPTR ram;
  497.         ram = Lock("RAM:", ACCESS_READ);
  498.         dirlock = CurrentDir(ram);
  499.         CurrentDir(dirlock);
  500.         UnLock(ram);
  501.     }
  502.     if(dirlock==0)
  503.         return 0;
  504.  
  505.     /* FIB must be long word aligned, and aztec doesn't guarantee this, so: */
  506.     if((FIB = AllocMem(sizeof(struct FileInfoBlock), MEMF_PUBLIC)) == 0) {
  507.         UnLock(dirlock);
  508.         return 0;
  509.     }
  510.     if(!Examine(dirlock, FIB)) {
  511.         UnLock(dirlock);
  512.         FreeMem(FIB, sizeof(struct FileInfoBlock));
  513.         return 0;
  514.     }
  515.     if(FIB->fib_DirEntryType < 0) {
  516.         UnLock(dirlock);
  517.         FreeMem(FIB, sizeof(struct FileInfoBlock));
  518.         return 0;
  519.     }
  520.     NewList = 0;
  521.     NewCount = 0;
  522.     while(ExNext(dirlock, FIB)) {
  523.         NewCount += 1;
  524.         ptr = (struct dirent *)malloc(sizeof(struct dirent));
  525.         if(ptr==0) {
  526.             FreeList(NewList);
  527.             UnLock(dirlock);
  528.             FreeMem(FIB, sizeof(struct FileInfoBlock));
  529.             return 0;
  530.         }
  531.         ptr->nextfile = NewList;
  532.         ptr->filetype = (FIB->fib_DirEntryType<0)?FILETYPE:DIRTYPE;
  533.         ptr->filename = malloc(strlen(FIB->fib_FileName)+1);
  534.         if(ptr->filename == 0) {
  535.             FreeList(ptr);
  536.             UnLock(dirlock);
  537.             FreeMem(FIB, sizeof(struct FileInfoBlock));
  538.             return 0;
  539.         }
  540.         strcpy(ptr->filename, FIB->fib_FileName);
  541.         NewList = ptr;
  542.     }
  543.     FreeMem(FIB, sizeof(struct FileInfoBlock));
  544.     if(DirName[0]) {
  545.         UnLock(dirlock);
  546.     }
  547.     NewTable = malloc(sizeof(struct dirent *)*NewCount);
  548.     if(NewTable==0) {
  549.         FreeList(NewList);
  550.         return 0;
  551.     }
  552.     FreeList(NameList);
  553.     NameList = NewList;
  554.     if(NameTable) free(NameTable);
  555.     NameTable = NewTable;
  556.  
  557.     if(PatName[0]==0)
  558.         SetPatName("#?");
  559.  
  560.     State = DIRECTORY;
  561.     Selected = -1;
  562.  
  563.     ReCalcPattern();
  564. }
  565.  
  566. static ReadVol()
  567. {
  568.     struct dirent *NewList, **NewTable, *ptr;
  569.     int NewCount;
  570.     char name[MAXNAME];
  571.  
  572.     if(State != DIRECTORY) {
  573.         NameTable = 0;
  574.         NameList = 0;
  575.     }
  576.     OpenVolList();
  577.     NewList = 0;
  578.     NewCount = 0;
  579.     while(ReadVolList(name)) {
  580.         NewCount += 1;
  581.         ptr = (struct dirent *)malloc(sizeof(struct dirent));
  582.         if(ptr==0) {
  583.             FreeList(NewList);
  584.             return 0;
  585.         }
  586.         ptr->nextfile = NewList;
  587.         ptr->filetype = VOLTYPE;
  588.         ptr->filename = malloc(strlen(name)+1);
  589.         if(ptr->filename == 0) {
  590.             FreeList(ptr);
  591.             return 0;
  592.         }
  593.         strcpy(ptr->filename, name);
  594.         NewList = ptr;
  595.     }
  596.     CloseVolList();
  597.     NewTable = malloc(sizeof(struct dirent *)*NewCount);
  598.     if(NewTable==0) {
  599.         FreeList(NewList);
  600.         return 0;
  601.     }
  602.     FreeList(NameList);
  603.     NameList = NewList;
  604.     if(NameTable) free(NameTable);
  605.     NameTable = NewTable;
  606.  
  607.     if(PatName[0]==0)
  608.         SetPatName("#?");
  609.  
  610.     State = DIRECTORY;
  611.     Selected = -1;
  612.  
  613.     ReCalcPattern();
  614. }
  615.  
  616. static WORD PatCode[128];
  617.  
  618. static patcomp()
  619. {
  620.     /* This is a judgement call: that no pattern should be equivalent
  621.        to "#?". Perhaps it should do this invisibly, by adding a
  622.        pointer to the real pattern name and making it PatName or "#?"
  623.        as appropriate. */
  624.  
  625.     if(!PatName[0])
  626.         SetPatName("#?");
  627.     return CmplPat(PatName, PatCode);
  628. }
  629.  
  630. static patmatch(name)
  631. {
  632.     return Match(PatName, PatCode, name);
  633. }
  634.  
  635. /* this routine does a true dictionary search:
  636.  *
  637.  *        Devs < devs but Devs > devices
  638.  */
  639. static table_compare(p1, p2)
  640. struct dirent **p1, **p2;
  641. {
  642.     char *s1, *s2;
  643.     char c1, c2;
  644.     char firstdiff;
  645.  
  646.     s1 = (*p1)->filename;
  647.     s2 = (*p2)->filename;
  648.     firstdiff = 0;
  649.  
  650.     while(*s1 && *s2) {
  651.         c1 = *s1++;
  652.         c2 = *s2++;
  653.         if(firstdiff==0)
  654.             firstdiff = c1 - c2;
  655.         if(c1>='A' && c1<='Z') c1 = c1+'@';
  656.         if(c2>='A' && c2<='Z') c2 = c2+'@';
  657.         if(c1 != c2)
  658.             return c1 - c2;
  659.     }
  660.     return firstdiff;
  661. }
  662.  
  663. static sort_table()
  664. {
  665.     qsort(NameTable, NumFiles, sizeof(struct dirent *), table_compare);
  666.     return 1;
  667. }
  668.  
  669. static ReCalcPattern()
  670. {
  671.     if(State != DIRECTORY)
  672.         ReadNewDir();
  673.     else {
  674.         struct dirent *ptr;
  675.         patcomp();
  676.  
  677.         NumFiles = 0;
  678.         for(ptr = NameList; ptr; ptr=ptr->nextfile) {
  679.             /* Directories always match. Is this good? */
  680.             if(ptr->filetype == DIRTYPE ||
  681.                ptr->filetype == VOLTYPE ||
  682.                patmatch(ptr->filename)) {
  683.                 NameTable[NumFiles] = ptr;
  684.                 NumFiles++;
  685.             }
  686.         }
  687.         sort_table();
  688.         CalcPropGadget();
  689.         Selected = -1;
  690.         PrintFileNames();
  691.     }
  692. }
  693.  
  694. static SetGadgetText(id, text)
  695. int id;
  696. char *text;
  697. {
  698.     int position;
  699.  
  700.     position = RemoveGadget(STD_Window, G(id));
  701.     if(position != -1) {
  702.         strcpy(SBuffer[id], text);
  703.         STD_String[id].BufferPos = strlen(text);
  704.         position = AddGadget(STD_Window, G(id), -1);
  705.         if(position != -1)
  706.             RefreshGadgets(G(id), STD_Window, NULL);
  707.     }
  708. }
  709.  
  710. static SetDirName(name)
  711. char *name;
  712. {
  713.     char buffer[MAXFULL+1], *ptr;
  714.     int index;
  715.     char lastchar;
  716.  
  717.     /* Can't enter a file name too long. */
  718.     if(strlen(DirName) + strlen(name) + 1 > MAXFULL) {
  719.         DisplayBeep();
  720.         return 0;
  721.     }
  722.     index = 0;
  723.     lastchar = 0;
  724.     for(ptr = DirName; *ptr; ptr++)
  725.         buffer[index++] = lastchar = *ptr;
  726.     if(lastchar!='/' && lastchar!=':' && lastchar!=0)
  727.         buffer[index++] = '/';
  728.     strcpy(&buffer[index], name);
  729.     SetGadgetText(DIRID, buffer);
  730.     SetGadgetText(FILID, "");
  731.     return 1;
  732. }
  733.  
  734. static ReadParDir()
  735. {
  736.     int i;
  737.     int ptr;
  738.  
  739.     ptr = -1;
  740.     for(i = 0; DirName[i]; i++)
  741.         if(DirName[i]==':' || DirName[i]=='/')
  742.             ptr = i;
  743.     if(ptr>=0) {
  744.         SetGadgetText(FILID, &DirName[ptr+1]);
  745.         if(ptr==0 || DirName[ptr]==':')
  746.             ptr++;
  747.         DirName[ptr] = 0;
  748.         SetGadgetText(DIRID, DirName);
  749.     } else {
  750.         SetGadgetText(FILID, DirName);
  751.         if(i)
  752.             SetGadgetText(DIRID, "");
  753.         else
  754.             SetGadgetText(DIRID, "/");
  755.     }
  756.     ReadNewDir();
  757.     return 1;
  758. }
  759.  
  760. static SetFileName(name)
  761. char *name;
  762. {
  763.     /* Can't enter a file name too long. */
  764.     if(strlen(DirName) + strlen(name) + 1 > MAXFULL) {
  765.         DisplayBeep();
  766.         return 0;
  767.     }
  768.     SetGadgetText(FILID, name);
  769.     return 1;
  770. }
  771.  
  772. static SetPatName(name)
  773. char *name;
  774. {
  775.     SetGadgetText(PATID, name);
  776. }
  777.  
  778. static ProcessGadget(id)
  779. int id;
  780. {
  781.     switch(id) {
  782.         case DIRID: ReadNewDir(); break;
  783.         case FILID: DoneFlag = 1; break;
  784.         case PATID: ReCalcPattern(); break;
  785.         case BARID: CalcFilePosition(); break;
  786.         case YESID: DoneFlag = 1; break;
  787.         case CANID: DoneFlag = -1; break;
  788.         case VOLID: ReadVol(); break;
  789.         case PARID: ReadParDir(); break;
  790.     }
  791. }
  792.  
  793. static ProcessMouse(x, y, code, seconds, micros)
  794. int x, y, code;
  795. {
  796.     int NewSelected;
  797.     static int oseconds = 0, omicros = 0;
  798.  
  799.     if(x<HOMEX || y<HOMEY || x>=LASTX || y>=LASTY)
  800.         return;
  801.     if((code&SELECTUP) == SELECTUP)
  802.         return;
  803.     if(State != DIRECTORY) {
  804.         ReadNewDir();
  805.         return;
  806.     }
  807.     NewSelected = (y-HOMEY)/CHSIZ + FirstFile;
  808.     if(NewSelected == Selected) {
  809.         if(Selected != -1) {
  810.             if(DoubleClick(oseconds, omicros, seconds, micros)) {
  811.                 if(NameTable[Selected]->filetype == DIRTYPE) {
  812.                     if(SetDirName(NameTable[Selected]->filename))
  813.                         ReadNewDir();
  814.                 } else if(NameTable[Selected]->filetype == VOLTYPE) {
  815.                     SetGadgetText(DIRID, NameTable[Selected]->filename);
  816.                     SetGadgetText(FILID, "");
  817.                     ReadNewDir();
  818.                 } else {
  819.                     if(!SetFileName(NameTable[Selected]->filename))
  820.                         Selected = -1;
  821.                     DoneFlag = 1;
  822.                 }
  823.             }
  824.         }
  825.     } else {
  826.         if(Selected != -1 &&
  827.            Selected>=FirstFile && Selected<FirstFile+MAXFILES)
  828.             PrintName(Selected, 0);
  829.         Selected = NewSelected;
  830.         if(Selected>=NumFiles)
  831.             Selected = -1;
  832.         else {
  833.             if(SetFileName(NameTable[Selected]->filename))
  834.                 PrintName(Selected, 1);
  835.             else
  836.                 Selected = -1;
  837.         }
  838.     }
  839.     oseconds = seconds;
  840.     omicros = micros;
  841. }
  842.  
  843. stdfile(title, deffile, defpat, name)
  844. char *title, *deffile, *defpat, *name;
  845. {
  846.     if(title)
  847.         STD_NewWindow.Title = (UBYTE *)title;
  848.     else
  849.         STD_NewWindow.Title = (UBYTE *)"Enter File Name";
  850.     if(deffile) {
  851.         int i;
  852.         for(i = strlen(deffile)-1; i>=0; i--) {
  853.             if(deffile[i]==':' || deffile[i]=='/') {
  854.                 int hold;
  855.                 strcpy(FileName, &deffile[i+1]);
  856.                 if(deffile[i]==':')
  857.                     i++;
  858.                 hold = deffile[i];
  859.                 deffile[i] = 0;
  860.                 strcpy(DirName, deffile);
  861.                 deffile[i] = hold;
  862.                 break;
  863.             }
  864.         }
  865.         if(i<0) {
  866.             strcpy(FileName, deffile);
  867.             DirName[0] = 0;
  868.         }
  869.     } else {
  870.         DirName[0] = 0;
  871.         FileName[0] = 0;
  872.     }
  873.     if(defpat)
  874.         strcpy(PatName, defpat);
  875.     else
  876.         PatName[0] = 0;
  877.  
  878.     State = INITIAL;
  879.     NameTable = 0;
  880.     NameList = 0;
  881.  
  882.     if(OpenFileWindow()) {
  883.         struct IntuiMessage *msg;
  884.         DoneFlag = 0;
  885.         while(!DoneFlag) {
  886.             Wait(1<<STD_Window->UserPort->mp_SigBit);
  887.             while(msg = GetMsg(STD_Window->UserPort)) {
  888.                 switch(msg->Class) {
  889.                     case CLOSEWINDOW:
  890.                         DoneFlag = -1;
  891.                         break;
  892.                     case MOUSEBUTTONS:
  893.                         ProcessMouse(msg->MouseX, msg->MouseY,
  894.                             msg->Code,
  895.                             msg->Seconds, msg->Micros);
  896.                         break;
  897.                     case GADGETUP:
  898.                         ProcessGadget(
  899.                             ((struct Gadget *)msg->IAddress)->GadgetID
  900.                         );
  901.                         break;
  902.                     case REFRESHWINDOW:
  903.                         BeginRefresh(STD_Window);
  904.                         PaintFileWindow();
  905.                         EndRefresh(STD_Window, 1);
  906.                         break;
  907.                 }
  908.                 ReplyMsg(msg);
  909.             }
  910.         }
  911.  
  912.         CloseFileWindow();
  913.     }
  914.     else return 0;
  915.  
  916.     FreeList(NameList);
  917.     if(NameTable) free(NameTable);
  918.  
  919.     if(DoneFlag==1) {
  920.         int len;
  921.  
  922.         strcpy(name, DirName);
  923.         if(FileName[0]) {
  924.             if(len = strlen(name))
  925.                 if(name[len-1]!=':')
  926.                     strcat(name, "/");
  927.             strcat(name, FileName);
  928.             return 1;
  929.         }
  930.  
  931.         /* Here the user has accepted the name without providing a file
  932.            name. I return true, but false may be more appropriate. What
  933.            do you think? */
  934.         return 1;
  935.     }
  936.     return 0;
  937. }
  938.